﻿cmake_minimum_required(VERSION 3.10)

#----------------------- 默认配置参数 ----------------------

#工程名称（PROJECT_NAME 变量，默认取所在目录名称）
file(RELATIVE_PATH PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR}/.. ${CMAKE_CURRENT_LIST_DIR})

#源码文件扩展名
set(SRC_EXTS *.cpp *.c *.cc)

#头文件扩展名
set(HEADER_EXTS *.h *.hpp)  
  
#需要排除的文件(列表)
list(APPEND EXCLUDES ".*/CMakeFiles/.*") 

#依赖的库
set(LIBS )

#编译器名称（COMPILE_NAME 变量，默认取当前目录名称）
file(RELATIVE_PATH COMPILE_NAME ${CMAKE_BINARY_DIR}/.. ${CMAKE_BINARY_DIR})


#----------------------- 加载外部配置文件(用于修改覆盖默认配置参数) ----------------------
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/config_local.cmake")    
    set(CONFIG_F "${CMAKE_CURRENT_LIST_DIR}/config_local.cmake")    
else()
    set(CONFIG_F "${CMAKE_CURRENT_LIST_DIR}/config.cmake")    
endif()
include("${CONFIG_F}" OPTIONAL)


#-------------------- 生成一个默认版本头文件 --------------------
file(MAKE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/include")
if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/include/revision.h") 
file(WRITE "${CMAKE_CURRENT_LIST_DIR}/include/revision.h" //)
endif()

#----------------------- 查找所有源码文件和头文件 ----------------------
file(GLOB_RECURSE ALL_SRCS ${SRC_EXTS}) 
file(GLOB_RECURSE ALL_HEADERS ${HEADER_EXTS})
file(GLOB_RECURSE RC_SRCS *.rc)

#----------------------- 按EXLUDES变量过滤掉不需要编译的文件 ----------------------
foreach(EXCL IN LISTS EXCLUDES) 
    list(FILTER ALL_SRCS EXCLUDE REGEX ${EXCL})
    list(FILTER ALL_HEADERS EXCLUDE REGEX ${EXCL})
endforeach()


#----------------------- 将每个头文件所在目录添加到include ----------------------
foreach(FILENAME IN LISTS ALL_HEADERS)
    get_filename_component(DIRNAME ${FILENAME} DIRECTORY)    
    if(NOT "${DIRNAME}" IN_LIST INCS)
        list(APPEND INCS ${DIRNAME})        
    endif()
endforeach()
foreach(INC IN LISTS INCS)
    include_directories(${INC})
endforeach()


#----------------------- 查找编译器 ------------------------
find_program(COMPILE_EXE ${COMPILE_NAME}-gcc)
if("${COMPILE_EXE}" STREQUAL "COMPILE_EXE-NOTFOUND")    
    #message("-- Compiler: default")
else()
    message("-- Compiler: ${COMPILE_NAME}")
    set(CMAKE_C_COMPILER ${COMPILE_NAME}-gcc)
    set(CMAKE_CXX_COMPILER ${COMPILE_NAME}-g++)
    find_program(CMAKE_AR ${COMPILE_NAME}-ar)
    if("${CMAKE_AR}" STREQUAL  "CMAKE_AR-NOTFOUND")
        set(CMAKE_AR "${COMPILE_NAME}-gcc-ar")
    endif()
    if("${COMPILE_NAME}" MATCHES ".*mingw.*")
        set(CMAKE_SYSTEM_NAME Windows)
    else()
        set(CMAKE_SYSTEM_NAME Linux)
    endif()
endif()

#----------------------- 根据源码文件类型确定语言 ----------------------
set(HAS_CXX 0)
foreach(FILENAME IN LISTS ALL_SRCS)
    get_filename_component(EXTNAME ${FILENAME} EXT)    
    if(NOT ${EXTNAME} STREQUAL ".c")        
        set(HAS_CXX 1)    
    endif()
endforeach()
if(HAS_CXX)
project(${PROJECT_NAME} LANGUAGES C CXX)
else()
project(${PROJECT_NAME} LANGUAGES C)
endif()


#-------------------- RC文件依赖 --------------------
if(NOT "${RC_SRCS}" STREQUAL "")
    get_filename_component(DIRNAME ${RC_SRCS} DIRECTORY)    
    file(GLOB_RECURSE RC_DEPS ${DIRNAME}/*)
    list(REMOVE_ITEM RC_DEPS ${RC_SRCS})    
    set_source_files_properties("${RC_SRCS}" PROPERTIES OBJECT_DEPENDS "${RC_DEPS}")
    get_filename_component(COMPILER_DIR ${CMAKE_C_COMPILER} DIRECTORY)
    set(CMAKE_RC_COMPILER ${COMPILER_DIR}/windres)
endif()



#----------------- 不依赖 libstdc++.so libgcc_s.so -------------------------
if(NOT ${CMAKE_C_COMPILER_ID} STREQUAL MSVC) #not vc
if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
    link_libraries(-s) #剥离调试符号
    if("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
        link_libraries(-static)
    else()
        if(NOT EXISTS ${CMAKE_BINARY_DIR}/libstdc++.a)
            execute_process(COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=libstdc++.a OUTPUT_VARIABLE LIBSTDCXXPATH OUTPUT_STRIP_TRAILING_WHITESPACE)
            if(${WIN32})
                execute_process(COMMAND copy /b /y ${LIBSTDCXXPATH} . WORKING_DIRECTORY "${CMAKE_BINARY_DIR}")
            else()
                execute_process(COMMAND ln -s ${LIBSTDCXXPATH} WORKING_DIRECTORY "${CMAKE_BINARY_DIR}")
            endif()
        endif()
        link_libraries(-L. -static-libgcc)
    endif()
endif()    
endif()

#----------------------- 其他编译参数设置 ----------------------

#导出compile_commands.json文件
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)


#-------------------- 编译器默认选项 --------------------
add_compile_options(-DUNICODE -D_UNICODE)
link_libraries(user32 gdi32 mf mfplat mfuuid strmiids)
if(${CMAKE_C_COMPILER_ID} STREQUAL MSVC) #vc
    add_compile_options(-D_CRT_SECURE_NO_WARNINGS /utf-8)    
else() #gcc
    add_compile_options(-Wall)    
    link_libraries(-municode)
    if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
        link_libraries(-Wl,--subsystem,windows)    
    endif()
endif()

#--------------------- 拷贝资源文件到输出目录 ----------------------
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/resource)
    file(GLOB_RECURSE RESS RELATIVE "${CMAKE_CURRENT_LIST_DIR}/resource" "${CMAKE_CURRENT_LIST_DIR}/resource/*" )
    foreach(F IN LISTS RESS)
        get_filename_component(DIRNAME ${F} DIRECTORY)    
        file(COPY ${CMAKE_CURRENT_LIST_DIR}/resource/${F} DESTINATION ${CMAKE_BINARY_DIR}/${DIRNAME})
    endforeach()
endif()

#----------------------- 使用外部build.cmake ----------------------
if(DEFINED CONFIG_DIR)
include(${CONFIG_DIR}/build.cmake OPTIONAL)
if(EXISTS ${CONFIG_DIR}/build.cmake)    
    return()
endif()
endif()

#-------------------- 编译主程序 (debug版本默认以_test结尾，release版默认为工程名称) --------------------
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
    set(MAIN_TARGET_NAME ${PROJECT_NAME}_test)
else()
    set(MAIN_TARGET_NAME ${PROJECT_NAME})    
endif()
add_executable(${MAIN_TARGET_NAME} ${ALL_SRCS} ${RC_SRCS} ${LIB_SRCS})
if(${CMAKE_C_COMPILER_ID} STREQUAL MSVC) #vc
    set_target_properties(${MAIN_TARGET_NAME} PROPERTIES LINK_FLAGS "/manifest:no /subsystem:windows")   
endif()
#-------------------- 链接主程序依赖的库 --------------------
foreach(DEP IN LISTS LIBS)
    target_link_libraries(${MAIN_TARGET_NAME} ${DEP} )
    add_dependencies(${MAIN_TARGET_NAME} ${DEP})        
endforeach()


#-------------------- 链接assets资源文件 --------------------
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/assets)
    file(COPY ${CMAKE_CURRENT_LIST_DIR}/assets DESTINATION .)
    set(ASSETS_OPT  -Wl,--format=binary)
    set(ASSETS_FILES  )    
    file(GLOB_RECURSE RESS RELATIVE "${CMAKE_CURRENT_LIST_DIR}/assets" "${CMAKE_CURRENT_LIST_DIR}/assets/*" )
    foreach(F IN LISTS RESS)
        #message(${F})        
        set(ASSETS_OPT ${ASSETS_OPT} -Wl,assets/${F})
        set(ASSETS_FILES  ${ASSETS_FILES} ${CMAKE_CURRENT_LIST_DIR}/assets/${F})        
    endforeach()
    set(ASSETS_OPT ${ASSETS_OPT} -Wl,--format=default)    
    target_link_options(${MAIN_TARGET_NAME} PUBLIC ${ASSETS_OPT})
    set_target_properties(${MAIN_TARGET_NAME} PROPERTIES LINK_DEPENDS "${ASSETS_FILES}")
endif()

#-------------------- assets资源列表写入到头文件 --------------------
if(DEFINED RESS)
    set(ASSETS_SIM  "#pragma once\n")
    set(ASSETS_ITEM  "#define ASSETS_FILE_LIST {\\")
    foreach(F IN LISTS RESS)        
        string(REPLACE . _ SIM1 ${F})
        string(REPLACE / _ SIM ${SIM1})
        set(ASSETS_SIM  "${ASSETS_SIM}\nextern const unsigned char _binary_assets_${SIM}_start[];")
        set(ASSETS_SIM  "${ASSETS_SIM}\nextern const unsigned char _binary_assets_${SIM}_end[];")
        set(ASSETS_ITEM "${ASSETS_ITEM}\n    {\"${F}\", _binary_assets_${SIM}_start, _binary_assets_${SIM}_end},\\")
    endforeach()
    set(ASSETS_ITEM "${ASSETS_ITEM}\n}\n")
    set(ASSETS_SIM "${ASSETS_SIM}\n\n")    
    file(WRITE "${CMAKE_CURRENT_LIST_DIR}/include/assets.h" "${ASSETS_SIM}")
    file(APPEND "${CMAKE_CURRENT_LIST_DIR}/include/assets.h" "${ASSETS_ITEM}")
endif()


#-------------------- 引入外部包 --------------------
set(PROJECT_NAME ${MAIN_TARGET_NAME})
include(packages.cmake OPTIONAL)








